package me.magicall.db.springjdbc;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import me.magicall.db.dao.Dao;
import me.magicall.db.meta.TableMeta;
import me.magicall.db.meta.TableMetaAccessor;
import me.magicall.db.model.BaseModel.MapModel;
import me.magicall.db.util.DbUtil;
import me.magicall.db.util.PageInfo;
import me.magicall.db.util.ReturnKeyAndAffect;
import me.magicall.util.kit.Kits;

import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

public class DaoFactory {
	private NamedParameterJdbcOperations jdbc;
	private TableMetaAccessor tableMetaAccessor;

	private final ConcurrentHashMap<String, Dao<?>> map = new ConcurrentHashMap<String, Dao<?>>();

	public DaoFactory() {
		super();
	}

	public DaoFactory(final JdbcOperations jdbc, final TableMetaAccessor tableMetaAccessor) {
		super();
		this.jdbc = new NamedParameterJdbcTemplate(jdbc);
		this.tableMetaAccessor = tableMetaAccessor;
	}

	public DaoFactory(final NamedParameterJdbcOperations jdbc, final TableMetaAccessor tableMetaAccessor) {
		super();
		this.jdbc = jdbc;
		this.tableMetaAccessor = tableMetaAccessor;
	}

	public boolean containsModelName(final String modelName) {
		return getMapModelDao(modelName) != EMPTY_DAO;
	}

	@SuppressWarnings("unchecked")
	public Dao<MapModel<?>> getMapModelDao(final String modelName) {
		Dao<MapModel<?>> dao = (Dao<MapModel<?>>) map.get(modelName);
		if (dao == null) {
			final TableMeta tableMeta = tableMetaAccessor.getTableMetaUsingModelName(modelName);
			if (tableMeta == null) {
				dao = EMPTY_DAO;
			} else {
				dao = new MapModelDaoImpl(tableMeta, jdbc, tableMetaAccessor);
			}
			map.putIfAbsent(modelName, dao);
			map.putIfAbsent(DbUtil.javaNameToDbName(modelName), dao);
		}
		return dao;
	}

	public Dao<MapModel<?>> getMapModelDao(final Class<? extends Enum<?>> enumClass) {
		return getMapModelDao(enumClass.getSimpleName());
	}

	@SuppressWarnings("rawtypes")
	private static final Dao EMPTY_DAO = new Dao() {

		@Override
		public Object fill(final Object modelOnlyWithId) {
			return null;
		}

		@Override
		public Collection fill(final Object... modelOnlyWithId) {
			return Kits.LIST.emptyValue();
		}

		@Override
		public Collection fill(final Collection modelOnlyWithId) {
			return Kits.LIST.emptyValue();
		}

		@Override
		public ReturnKeyAndAffect addReturnKey(final Object model) {
			return ReturnKeyAndAffect.EMPTY;
		}

		@Override
		public int[] add(final Collection models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int update(final Object model) {
			return 0;
		}

		@Override
		public int[] update(final Object... models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int[] update(final Collection models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public boolean addOrUpdate(final Object model) {
			return false;
		}

		@Override
		public int[] addOrUpdate(final Object... models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int[] addOrUpdate(final Collection models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int del(final Object model) {
			return 0;
		}

		@Override
		public int[] del(final Object... models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public int[] del(final Collection models) {
			return Kits.INT.emptyPrimitiveArray();
		}

		@Override
		public Object get(final Comparable id) {
			return null;
		}

		@Override
		public List getList(final Map paramMap, final PageInfo pageInfo) {
			return Kits.LIST.emptyValue();
		}

		@Override
		public List getList(final Map paramMap, final int size) {
			return Kits.LIST.emptyValue();
		}

		@Override
		public List getList(final Map paramMap) {
			return Kits.LIST.emptyValue();
		}

		@Override
		public int count(final Map paramMap) {
			return 0;
		}

		@Override
		public Collection listUsingIds(final Object... ids) {
			return Kits.LIST.emptyValue();
		}

		@Override
		public Collection listUsingIds(final Collection ids) {
			return Kits.LIST.emptyValue();
		}

		@Override
		public Collection all() {
			return Kits.LIST.emptyValue();
		}

		@Override
		public int allCount() {
			return 0;
		}

		@Override
		public int del(final Comparable id) {
			return 0;
		}

		@Override
		public ReturnKeyAndAffect addReturnKey(final Object... models) {
			return ReturnKeyAndAffect.EMPTY;
		}

		@Override
		public ReturnKeyAndAffect addReturnKey(final Collection models) {
			return ReturnKeyAndAffect.EMPTY;
		}

		@Override
		public int addIfAbsent(final Object... models) {
			return 0;
		}

		@Override
		public int addIfAbsent(final Collection models) {
			return 0;
		}

		@Override
		public boolean add(final Object model) {
			return false;
		}

		@Override
		public int[] add(final Object... models) {
			return Kits.INT.emptyPrimitiveArray();
		}
	};

}
